/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.atomojo.tools;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;
import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeRequest;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Cookie;
import org.restlet.data.CookieSetting;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.engine.header.Header;
import org.restlet.engine.util.DateUtils;
import org.restlet.util.Series;

/**
 *
 * @author alex
 */
public class UserAgent {

   static ChallengeScheme HTTP_BEARER = new ChallengeScheme("HTTP_Bearer","Bearer");
   protected class ServerContext {
      String server;
      ChallengeResponse token;
      Series<Cookie> cookies;
      String username;
      String password;
      ServerContext(String server) {
         this.server = server;
         this.token = null;
         this.cookies = new Series<Cookie>(Cookie.class);
         this.username = null;
         this.password = null;
      }
   }
   Context context;
   Client client;
   Map<String,ServerContext> servers;
   public UserAgent(Context context) {
      this.context = context;
      this.client = context.getClientDispatcher();
      this.servers = new TreeMap<String,ServerContext>();
   }
   
   public Context getContext() {
      return context;
   }
   
   public Logger getLogger() {
      return context.getLogger();
   }
   
   protected ServerContext getServerContext(String server)
   {
      ServerContext serverContext = servers.get(server);
      if (serverContext==null) {
         getLogger().info("New server context: "+server);
         serverContext = new ServerContext(server);
         servers.put(server,serverContext);
      }
      return serverContext;
   }
   
   public void setIdentity(String server,String username, String password) {
      getLogger().info("Setting credentials for "+username+" for "+server);
      ServerContext serverContext = getServerContext(server);
      serverContext.username = username;
      serverContext.password = password;
   }
   
   public void setAccessToken(String server,String token) {
      getLogger().info("Setting token "+token+" for "+server);
      ServerContext serverContext = getServerContext(server);
      ChallengeResponse tokenResponse = new ChallengeResponse(HTTP_BEARER);
      tokenResponse.setRawValue(token);
      serverContext.token = tokenResponse;
   }
   
   public Request newRequest(Method method,Reference href) {
      Request request = new Request(method,href);
      String server = request.getResourceRef().getHostIdentifier();
      ServerContext serverContext = getServerContext(server);
      request.setCookies(serverContext.cookies);
      if (serverContext.token!=null) {
         request.setChallengeResponse(serverContext.token);
      }
      return request;
   }
   
   public Response attemptCall(Request request) {
      Response response = client.handle(request);
      String server = request.getResourceRef().getHostIdentifier();
      ServerContext serverContext = getServerContext(server);
      if (serverContext.username!=null && response.getStatus().equals(Status.CLIENT_ERROR_UNAUTHORIZED)) {
         getLogger().info("Retrying with challenge response...");
         request.setChallengeResponse(null);
         for (ChallengeRequest challenge : response.getChallengeRequests()) {
            request.setChallengeResponse(new ChallengeResponse(challenge,response,serverContext.username,serverContext.password.toCharArray()));
         }
         if (request.getChallengeResponse()!=null) {
            response = client.handle(request);
         }
      }
      filterResponse(request,response);
      return response;
   }
   
   public void filterResponse(Request request,Response response) {
      String server = request.getResourceRef().getHostIdentifier();
      ServerContext serverContext = getServerContext(server);
      for (CookieSetting setting : response.getCookieSettings()) {
         getLogger().info("Setting cookie: "+setting.getName()+"="+setting.getValue());
         serverContext.cookies.removeAll(setting.getName());
         serverContext.cookies.add(setting.getName(),setting.getValue());
      }
   }
   
   public void addSlug(Request request,String slug) {
      Series<Header> headers = (Series<Header>)request.getAttributes().get("org.restlet.http.headers");
      if (headers==null) {
         headers = new Series<Header>(Header.class);
         request.getAttributes().put("org.restlet.http.headers", headers);
      }
      headers.add("Slug", Reference.encode(slug));
   }
   public void addXLastModified(Request request,Date date) {
      Series<Header> headers = (Series<Header>)request.getAttributes().get("org.restlet.http.headers");
      if (headers==null) {
         headers = new Series<Header>(Header.class);
         request.getAttributes().put("org.restlet.http.headers", headers);
      }
      headers.add("X-Last-Modified", DateUtils.format(date));
   }
}
